#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
污染类型缓存服务
分析 pollution_types表和pollution_type_examples的字段和实际数据库表的差异，调整模型对象属性
缓存 pollution_types表和pollution_type_examples的数据，使用memory缓存，使用PollutionTypeExample和PollutionType模型
提供 reload函数，实现从数据库中加载，并替换缓存内容的功能
提供 get_pollution_types函数，返回所有污染类型
"""

from typing import Dict, Any, List, Optional, Tuple, Union
import threading
import time
from datetime import datetime
from models.pollution_type import PollutionType, PollutionTypeExample
from core.database import get_db_session
from core.logging_config import get_logger

logger = get_logger("pollution_types_cache")



class PollutionTypesCache:
    """污染类型缓存管理器"""

    def __init__(self):
        # 使用线程锁保证并发安全
        self._lock = threading.RLock()

        # 缓存结构: {customer_id: {"pollution_types": {code: type_object}, "examples": {type_id: [example_objects]}}}
        self._cache: Dict[str, Dict[str, Any]] = {}

        # 缓存统计信息
        self._stats = {
            "load_count": 0,
            "reload_count": 0,
            "hit_count": 0,
            "miss_count": 0,
            "last_load_time": None,
            "last_reload_time": None
        }

        # 缓存配置
        self._config = {
            "enable_cache": True,
            "cache_ttl": 3600,  # 1小时过期
            "auto_reload": True
        }

    def _get_cache_key(self, customer_id: str) -> str:
        """获取缓存键"""
        return f"pollution_types_{customer_id}"

    def _is_cache_expired(self, customer_id: str) -> bool:
        """检查缓存是否过期"""
        if not self._config["enable_cache"]:
            return True

        cache_key = self._get_cache_key(customer_id)
        if cache_key not in self._cache:
            return True

        cache_data = self._cache[cache_key]
        if "timestamp" not in cache_data:
            return True

        cache_time = cache_data["timestamp"]
        current_time = time.time()
        return (current_time - cache_time) > self._config["cache_ttl"]

    def _load_from_database(self, customer_id: str) -> Dict[str, Any]:
        """从数据库加载污染类型数据"""
        logger.info(f"开始从数据库加载客户 {customer_id} 的污染类型数据")

        cache_data = {
            "pollution_types": {},
            "examples": {},
            "timestamp": time.time(),
            "customer_id": customer_id
        }

        try:
            with get_db_session() as db:
                # 加载污染类型数据
                pollution_types = db.query(PollutionType).filter(
                    PollutionType.customer_id == customer_id,
                    PollutionType.is_active == True
                ).order_by(PollutionType.sort_order, PollutionType.code).all()

                # 直接存储模型对象，不转换为字典
                for ptype in pollution_types:
                    cache_data["pollution_types"][ptype.code] = ptype

                # 加载样例数据
                examples = db.query(PollutionTypeExample).filter(
                    PollutionTypeExample.customer_id == customer_id,
                    PollutionTypeExample.is_active == True
                ).order_by(PollutionTypeExample.created_at.desc()).all()

                # 直接存储样例模型对象
                for example in examples:
                    type_id = example.pollution_type_id

                    if type_id not in cache_data["examples"]:
                        cache_data["examples"][type_id] = []
                    cache_data["examples"][type_id].append(example)

                logger.info(f"成功加载客户 {customer_id} 的数据: {len(pollution_types)} 个污染类型, {len(examples)} 个样例")

        except Exception as e:
            logger.error(f"从数据库加载客户 {customer_id} 数据失败: {str(e)}")
            raise

        return cache_data

    def reload(self, customer_id: str = PollutionType.default_customer) -> bool:
        """
        重新加载缓存数据
        :param customer_id: 客户ID，如果为None则重新加载所有客户的数据
        :return: 是否成功
        """
        try:
            with self._lock:
                if customer_id:
                    # 重新加载指定客户的数据
                    cache_key = self._get_cache_key(customer_id)
                    cache_data = self._load_from_database(customer_id)
                    self._cache[cache_key] = cache_data

                    self._stats["reload_count"] += 1
                    self._stats["last_reload_time"] = datetime.now()

                    logger.info(f"成功重新加载客户 {customer_id} 的缓存数据")
                else:
                    # 重新加载所有客户的数据
                    # 这里需要先获取所有客户ID，然后逐个加载
                    with get_db_session() as db:
                        # 获取所有有污染类型的客户ID
                        customer_ids = db.query(PollutionType.customer_id).distinct().all()
                        customer_ids = [cid[0] for cid in customer_ids]

                    for cid in customer_ids:
                        cache_key = self._get_cache_key(cid)
                        cache_data = self._load_from_database(cid)
                        self._cache[cache_key] = cache_data

                    self._stats["reload_count"] += 1
                    self._stats["last_reload_time"] = datetime.now()

                    logger.info(f"成功重新加载所有客户的缓存数据，共 {len(customer_ids)} 个客户")

                return True

        except Exception as e:
            logger.error(f"重新加载缓存数据失败: {str(e)}")
            return False

    def get_pollution_types(self, customer_id: str = PollutionType.default_customer, parent_code: str = None, level: int = None) -> List[PollutionType]:
        """
        获取污染类型列表
        :param customer_id: 客户ID
        :param parent_code: None 返回所有数据，"" 返回 parent_code = "" 的数据,其它 则返回 数据库字段parent_code = 参数内容的数据。
        :param level: 1 返回一级数据，2 返回二级数据，3 返回三级数据，None 返回所有符合条件的数据
        :return: 污染类型模型对象列表
        """
        try:
            with self._lock:
                cache_key = self._get_cache_key(customer_id)

                # 检查缓存是否存在或过期
                if self._is_cache_expired(customer_id):
                    # 缓存不存在或过期，重新加载
                    cache_data = self._load_from_database(customer_id)
                    self._cache[cache_key] = cache_data

                    self._stats["load_count"] += 1
                    self._stats["last_load_time"] = datetime.now()
                    self._stats["miss_count"] += 1

                    logger.info(f"缓存未命中，重新加载客户 {customer_id} 的数据")
                else:
                    self._stats["hit_count"] += 1

                # 获取缓存数据
                cache_data = self._cache[cache_key]
                pollution_types = cache_data["pollution_types"]

                # 过滤数据
                filtered_types = []

                for type_code, type_obj in pollution_types.items():
                    # parent_code 过滤
                    if parent_code is not None:
                        if parent_code == "":
                            # 返回 parent_code 为空或None的数据
                            if type_obj.parent_code not in [None, "", "nan"]:
                                continue
                        else:
                            # 返回 parent_code 等于指定值的数据
                            if type_obj.parent_code != parent_code:
                                continue

                    # level 过滤
                    if level is not None:
                        if type_obj.level != level:
                            continue

                    filtered_types.append(type_obj)

                logger.debug(f"客户 {customer_id} 查询结果: parent_code={parent_code}, level={level}, 返回 {len(filtered_types)} 条记录")
                return filtered_types

        except Exception as e:
            logger.error(f"获取污染类型数据失败: {str(e)}")
            raise

    def get_pollution_type_by_code(self, customer_id: str = PollutionType.default_customer, code: str = None) -> Optional[PollutionType]:
        """
        根据代码获取污染类型
        :param customer_id: 客户ID
        :param code: 污染类型代码
        :return: 污染类型模型对象，不存在返回None
        """
        try:
            types = self.get_pollution_types(customer_id)
            if code is None:
                return types
            for ptype in types:
                if ptype.code == code:
                    return ptype
            return None
        except Exception as e:
            logger.error(f"根据代码获取污染类型失败: {str(e)}")
            return None

    def get_pollution_type_examples(self, customer_id: str = PollutionType.default_customer, pollution_type_id: int = None) -> List[PollutionTypeExample]:
        """
        获取污染类型样例
        :param customer_id: 客户ID
        :param pollution_type_id: 污染类型ID，None表示返回所有样例
        :return: 样例模型对象列表
        """
        try:
            with self._lock:
                cache_key = self._get_cache_key(customer_id)

                # 检查缓存是否存在或过期
                if self._is_cache_expired(customer_id):
                    # 缓存不存在或过期，重新加载
                    cache_data = self._load_from_database(customer_id)
                    self._cache[cache_key] = cache_data

                    self._stats["load_count"] += 1
                    self._stats["last_load_time"] = datetime.now()
                    self._stats["miss_count"] += 1

                    logger.info(f"缓存未命中，重新加载客户 {customer_id} 的数据")
                else:
                    self._stats["hit_count"] += 1

                # 获取缓存数据
                cache_data = self._cache[cache_key]
                examples_data = cache_data["examples"]

                # 过滤样例
                if pollution_type_id is not None:
                    return examples_data.get(pollution_type_id, [])
                else:
                    # 返回所有样例
                    all_examples = []
                    for type_examples in examples_data.values():
                        all_examples.extend(type_examples)
                    return all_examples

        except Exception as e:
            logger.error(f"获取污染类型样例失败: {str(e)}")
            return []

    def get_hierarchy_tree(self, customer_id: str = PollutionType.default_customer) -> List[Dict[str, Any]]:
        """
        获取层级树结构
        :param customer_id: 客户ID
        :return: 层级树结构（字典格式，便于前端使用）
        """
        try:
            # 获取所有污染类型
            all_types = self.get_pollution_types(customer_id)

            # 构建字典便于查找
            type_dict = {ptype.code: ptype for ptype in all_types}

            # 构建树结构
            tree = []
            for ptype in all_types:
                if not ptype.parent_code or ptype.parent_code in [None, "", "nan"]:
                    # 一级分类
                    tree.append(self._build_tree_node(ptype, type_dict))

            return tree

        except Exception as e:
            logger.error(f"获取层级树结构失败: {str(e)}")
            return []

    def _build_tree_node(self, ptype: PollutionType, type_dict: Dict[str, PollutionType]) -> Dict[str, Any]:
        """构建树节点"""
        node = {
            "id": ptype.id,
            "code": ptype.code,
            "name": ptype.name,
            "level": ptype.level,
            "description": ptype.description,
            "children": []
        }

        # 添加子节点
        for child_code, child_data in type_dict.items():
            if child_data.parent_code == ptype.code:
                node["children"].append(self._build_tree_node(child_data, type_dict))

        return node

    def get_cache_stats(self) -> Dict[str, Any]:
        """获取缓存统计信息"""
        with self._lock:
            stats = self._stats.copy()
            stats["cache_size"] = len(self._cache)
            stats["config"] = self._config.copy()
            return stats

    def clear_cache(self, customer_id: str = None) -> bool:
        """
        清除缓存
        :param customer_id: 客户ID，None表示清除所有缓存
        :return: 是否成功
        """
        try:
            with self._lock:
                if customer_id:
                    cache_key = self._get_cache_key(customer_id)
                    if cache_key in self._cache:
                        del self._cache[cache_key]
                        logger.info(f"已清除客户 {customer_id} 的缓存")
                else:
                    self._cache.clear()
                    logger.info("已清除所有缓存")

                return True

        except Exception as e:
            logger.error(f"清除缓存失败: {str(e)}")
            return False

    def update_config(self, config: Dict[str, Any]) -> None:
        """更新缓存配置"""
        with self._lock:
            self._config.update(config)
            logger.info(f"缓存配置已更新: {config}")


# 全局缓存实例
pollution_types_cache = PollutionTypesCache()


# 便捷函数
def get_pollution_types(customer_id: str = PollutionType.default_customer, parent_code: str = None, level: int = None) -> List[PollutionType]:
    """
    获取所有污染类型
    :param customer_id: 客户ID
    :param parent_code: None 返回所有数据，"" 返回 parent_code = "" 的数据,其它 则返回 数据库字段parent_code = 参数内容的数据。
    :param level: 1 返回一级数据，2 返回二级数据，3 返回三级数据，None 返回所有符合条件的数据
    :return: 污染类型模型对象列表
    """
    return pollution_types_cache.get_pollution_types(customer_id, parent_code, level)


def reload_pollution_types_cache(customer_id: str = PollutionType.default_customer) -> bool:
    """
    重新加载污染类型缓存
    :param customer_id: 客户ID，None表示重新加载所有客户的数据
    :return: 是否成功
    """
    return pollution_types_cache.reload(customer_id)


def get_pollution_type_examples(customer_id: str = PollutionType.default_customer, pollution_type_id: int = None) -> List[PollutionTypeExample]:
    """
    获取污染类型样例
    :param customer_id: 客户ID
    :param pollution_type_id: 污染类型ID，None表示返回所有样例
    :return: 样例模型对象列表
    """
    return pollution_types_cache.get_pollution_type_examples(customer_id, pollution_type_id)


def get_pollution_type_hierarchy(customer_id: str = PollutionType.default_customer) -> List[Dict[str, Any]]:
    """
    获取污染类型层级树
    :param customer_id: 客户ID
    :return: 层级树结构
    """
    return pollution_types_cache.get_hierarchy_tree(customer_id)